package fr.norsys.mapper.console.service;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.TreeSet;

import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import fr.norsys.mapper.console.exception.ApplicationException;
import fr.norsys.mapper.console.exception.FileException;
import fr.norsys.mapper.console.exception.MappingException;
import fr.norsys.mapper.console.exception.PropertyException;
import fr.norsys.mapper.console.model.Application;
import fr.norsys.mapper.console.model.Attribute;
import fr.norsys.mapper.console.model.Connection;
import fr.norsys.mapper.console.model.ApplicationNameComparator;
import fr.norsys.mapper.console.model.Resource;
import fr.norsys.mapper.console.model.ResourceNameComparator;
import fr.norsys.mapper.console.utils.UIDGenerator;

public class ApplicationServiceImpl implements ApplicationService {
	private final static Log log = LogFactory.getLog(PropertyServiceImpl.class);

	private String appliDirPath;

	private FileService fileService;

	private PropertyService propertyService;

	private ConnectionService connectionService;

	private MappingService mappingService;
	
	private static String xmlFileExt = ".xml";

	ApplicationServiceImpl(){
		super();
	}
	/**
	 * action to save an application in session
	 * 
	 * @param application :
	 *            bean of the application
	 * @param applications :
	 *            Collection of application beans
	 */
	public void save(Application application, Collection applications)
			throws ApplicationException {
		if (application.getId() == null || "".equals(application.getId())){
			add(application, applications);		
		}
		else{
			modify(application, applications);
		}
	}

	/**
	 * action to add an application in session
	 * 
	 * @param application :
	 *            bean of the application
	 * @param applications :
	 *            Collection of application beans
	 */
	private void add(Application application, Collection applications)
			throws ApplicationException {
		Application a = null;
		try {
			a = (Application) BeanUtils.cloneBean(application);
		} catch (Exception e) {
			throw new ApplicationException(
					"Impossible to clone application bean:" + application
							+ "=> " + e);
		}
		a.setId(UIDGenerator.generateId());
		applications.add(a);
		try {
			fileService.createNewFile(a.getName() + xmlFileExt, appliDirPath);
		} catch (FileException e1) {
			throw new ApplicationException(e1.toString());
		}
		try {
			mappingService.saveMapping(a, appliDirPath + a.getName()
					+ xmlFileExt);
		} catch (MappingException e) {
			throw new ApplicationException(e.toString());
		}
	}

	/**
	 * action to modify an application in session
	 * 
	 * @param application :
	 *            bean of the application
	 * @param applications :
	 *            Collection of application beans
	 */
	private void modify(Application appli, Collection applications)
			throws ApplicationException {
		Application application = appli;
		for (Iterator it = applications.iterator(); it.hasNext();) {
			Application a = (Application) it.next();
			if (application.getId().equals(a.getId())) {
				if (!application.getName().equals(a.getName())) {
					try {
						fileService
								.changeFileName(a.getName() + xmlFileExt, application
										.getName()
										+ xmlFileExt, appliDirPath);
					} catch (FileException e) {
						throw new ApplicationException(e.toString());
					}
				}
				fr.norsys.mapper.console.utils.BeanUtils.copyFilledProperties(
						a, application);
				application = a;
				return;
			}
		}
	}

	/**
	 * action to delete an application in session
	 * 
	 * @param id :
	 *            id of the application
	 * @param applications :
	 *            Collection of application beans
	 */
	public void delete(String id, Collection applications)
			throws ApplicationException {
		for (Iterator it = applications.iterator(); it.hasNext();) {
			Application a = (Application) it.next();
			if (a.getId().equals(id)) {
				applications.remove(a);
				try {
					fileService.deleteFile(a.getName() + xmlFileExt,
							appliDirPath);
				} catch (FileException e) {
					throw new ApplicationException(e.toString());
				}
				break;
			}
		}
	}

	/**
	 * action to get an application in session
	 * 
	 * @param id :
	 *            id of the application
	 * @param applications :
	 *            Collection of application beans
	 * @return Application
	 */
	public Application get(String id, Collection applications)
			throws ApplicationException {
		Application appli=null;
		for (Iterator it = applications.iterator(); it.hasNext();) {
			Application a = (Application) it.next();
			if (a.getId().equals(id)) {
				appli = a;
			}
		}
		return appli;
	}

	/**
	 * action to modify the connection of an application in session
	 * 
	 * @param application :
	 *            bean of the application
	 * @param applications :
	 *            Collection of application beans
	 * @param connections :
	 *            Collection of connection beans
	 * @throws FileException
	 */
	public void modifyConnection(Application application, String connectionName)
			throws ApplicationException {
		if (log.isDebugEnabled()) {
			log.debug(application);
			log.debug("connectionName=" + connectionName);
		}
		Map map = new HashMap();
		try {
			map = propertyService.getProperty(connectionService.getConnectionsDirPath()+connectionName+".properties");
		} catch (PropertyException e) {
			log.error(e);
		}
		Connection connection = new Connection(connectionName);
		fr.norsys.mapper.console.utils.BeanUtils.toObject(map, connection);
		application.setConnection(connection);
	}

	/**
	 * Action to delete a resource from the list in session
	 * 
	 * @param currentResource :
	 *            resource to delete
	 * @param application :
	 *            application of the resource
	 * @param applications :
	 *            list of applications
	 */
	public void deleteRes(String cur, Application application) throws ApplicationException {
		Application appl = application;
		Application a = appl;
		String currentResourceId = cur;
		Collection tempResources = new TreeSet(new ResourceNameComparator());
		for(Iterator resources = a.getResources().iterator(); resources.hasNext();){
			Resource r =(Resource)resources.next();
			if(!r.getId().equals(currentResourceId)){
				tempResources.add(r);
			}
		}
		a.setResources(tempResources);
		fr.norsys.mapper.console.utils.BeanUtils.copyFilledProperties(
						a, appl);
		appl=a;
	}

	public Collection getApplicationsFromFileSystem() throws ApplicationException {
		Collection applicationsNames = new ArrayList();
		try {
			applicationsNames = fileService.getFilesName(appliDirPath,
					xmlFileExt);
		} catch (FileException e) {
			log.error(e);
		}
		Collection applications = new TreeSet(new ApplicationNameComparator());
		Application a=null;
		for (Iterator i = applicationsNames.iterator(); i.hasNext();) {
			a=new Application((String) i.next());
			applications.add(a);
		}
		return applications;
	}

	public FileService getFileService() {
		return fileService;
	}

	public void setFileService(FileService fileService) {
		this.fileService = fileService;
	}

	/**
	 * Service to sort resources list in session
	 * @param resources
	 * @return
	 */
	public Collection sortResources(Map resources) {
		Collection sortedList=new ArrayList();
		Collection values = resources.values();
		String[] sortedNames=new String[values.size()];
		int a=0;
		for(Iterator it=values.iterator();it.hasNext();){
			sortedNames[a]=((Resource)it.next()).getName();
			a++;
		}
		Arrays.sort(sortedNames);
		for(int i=0;i<sortedNames.length;i++){
			for(Iterator it=values.iterator();it.hasNext();){
				Resource r=(Resource)it.next();
				if(r.getName().equals(sortedNames[i])){
					sortedList.add(r);
				}
			}
		}
		
		return sortedList;
	}
	
	/**
	 * Service to sort attributes list in session
	 * @param attributes
	 * @return
	 */
	public Collection sortAttributes(Map attributes) {
		Collection sortedList=new ArrayList();
		Collection values = attributes.values();
		String[] sortedNames=new String[values.size()];
		int a=0;
		for(Iterator it=values.iterator();it.hasNext();){
			sortedNames[a]=((Attribute)it.next()).getName();
			a++;
		}
		Arrays.sort(sortedNames);
		for(int i=0;i<sortedNames.length;i++){
			for(Iterator it=values.iterator();it.hasNext();){
				Attribute r=(Attribute)it.next();
				if(r.getName().equals(sortedNames[i])){
					sortedList.add(r);
				}
			}
		}
		
		return sortedList;
	}


	public String getAppliDirPath() {
		return appliDirPath;
	}

	public void setAppliDirPath(String appliDirPath) {
		this.appliDirPath = appliDirPath;
	}

	public PropertyService getPropertyService() {
		return propertyService;
	}

	public void setPropertyService(PropertyService propertyService) {
		this.propertyService = propertyService;
	}

	public MappingService getMappingService() {
		return mappingService;
	}

	public void setMappingService(MappingService mappingService) {
		this.mappingService = mappingService;
	}
	public ConnectionService getConnectionService() {
		return connectionService;
	}

	public void setConnectionService(ConnectionService connectionService) {
		this.connectionService = connectionService;
	}
}
